// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PARSING_REGEX_PATTERNS_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PARSING_REGEX_PATTERNS_H_

#include "base/containers/span.h"
#include "base/strings/string_piece.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_parsing/autofill_parsing_utils.h"
#include "components/autofill/core/browser/form_parsing/buildflags.h"
#include "components/autofill/core/common/language_code.h"
#include "third_party/abseil-cpp/absl/types/optional.h"

namespace autofill {

// A MatchPatternRef dereferences to a MatchingPattern.
class MatchPatternRef {
 public:
  MatchingPattern operator*() const;

 private:
  // Internally, a MatchPatternRef is represented as
  // - an index into the `kPatterns` array generated by
  //   transpile_regex_patterns.py, and
  // - a boolean that indicates whether the pattern is an ordinary or a
  //   supplementary one.
  //
  // An *ordinary* pattern corresponds exactly to an entry the JSON file.
  //
  // A *supplementary* pattern is an ordinary MatchingPattern which is
  // restricted to MatchAttribute::kName. That is, supplementary patterns only
  // apply to the field's HTML name, not to the field's user-visible label.
  //
  // We use this for English patterns: we augment non-English languages with the
  // English patterns, restricted to the Attribute::kName. The motivation is
  // that the coding language also of non-English pages is often English.
  //
  // Representing the distinction between ordinary and supplementary patterns in
  // MatchPatternRef saves us from storing the supplementary MatchingPatterns
  // explicitly and saves some binary size.
  //
  // The dereferencing operator implements the restriction to
  // MatchFieldType::kName of supplementary MatchPatternRef.

  // We choose a small integer to save memory in the generated arrays.
  // Since the generated code passes integer literals to the constructor, the
  // compiler will catch if the UnderlyingType is not sufficiently large.
  using UnderlyingType = int16_t;

  // A wrapper of the constructor used by the code generation.
  friend constexpr MatchPatternRef MakeMatchPatternRef(bool is_supplementary,
                                                       UnderlyingType index);
  friend class MatchPatternRefTestApi;

  constexpr MatchPatternRef(bool supplementary, UnderlyingType index)
      : value_(supplementary ? -index - 1 : index) {}

  constexpr bool is_supplementary() const { return value_ < 0; }

  constexpr size_t index() const {
    return is_supplementary() ? -value_ - 1 : value_;
  }

  // Encodes both whether the pattern is_supplementary() and the index().
  UnderlyingType value_;
};

// The different sets of patterns that are available.
// Each enum constant corresponds to a JSON file.
enum class PatternSource {
#if !BUILDFLAG(USE_INTERNAL_AUTOFILL_PATTERNS)
  // Patterns whose stability is above suspicion.
  kLegacy,
  kMaxValue = kLegacy
#else
  // Patterns whose stability is above suspicion.
  kLegacy,
  // The patterns applied for most users.
  kDefault,
  // Patterns that are being verified experimentally.
  kExperimental,
  // One step before `kExperimental`. These patterns are used only for
  // non-user-visible metrics.
  kNextGen,
  kMaxValue = kNextGen
#endif
};

// The active pattern and the available patterns depend on the build config and
// the Finch config.
PatternSource GetActivePatternSource();
DenseSet<PatternSource> GetNonActivePatternSources();

// Looks up the patterns for the given name and language.
// The name is typically a field type.
//
// If there are no patterns for the given name and language, falls back to the
// union of all patterns for the given type (across all languages).
//
// Hits a CHECK if there are no patterns for the given name at all.
//
// The returned patterns are sorted by their MatchingPattern::positive_score in
// decreasing order.
base::span<const MatchPatternRef> GetMatchPatterns(
    base::StringPiece name,
    absl::optional<LanguageCode> language_code,
    PatternSource pattern_source);

base::span<const MatchPatternRef> GetMatchPatterns(
    ServerFieldType type,
    absl::optional<LanguageCode> language_code,
    PatternSource pattern_source);

// Returns true iff there at least one pattern for some PatternSource and
// pattern name.
bool IsSupportedLanguageCode(LanguageCode language_code);

}  // namespace autofill

#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PARSING_REGEX_PATTERNS_H_
